package org.origin.centre.utils;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;

/**
 * 客户端工具类
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public final class ClientUtil {
    private static final BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter();

    /**
     * 根据提供的认证信息获取对应的客户端ID。
     *
     * @param authentication 用户的认证信息，预期为OAuth2AccessTokenAuthenticationToken类型，包含注册客户端的详细信息。
     * @return 如果认证信息中包含有效的注册客户端信息，则返回对应的客户端ID；否则返回null。
     */
    public static String getClientIdByAuthentication(Authentication authentication) {
        // 尝试将authentication转换为OAuth2AccessTokenAuthenticationToken类型
        if (authentication instanceof OAuth2AccessTokenAuthenticationToken authenticationToken) {
            // 从认证token中获取注册的客户端信息
            RegisteredClient registeredClient = authenticationToken.getRegisteredClient();
            // 如果存在注册的客户端，返回其客户端ID；否则返回null
            return registeredClient != null ? registeredClient.getClientId() : null;
        }
        // 如果认证信息不是预期的OAuth2AccessTokenAuthenticationToken类型，直接返回null
        return null;
    }

    /**
     * 通过OAuth请求获取客户端ID。
     * 该方法通过解析HttpServletRequest来尝试获取对应的客户端ID。
     *
     * @param request HttpServletRequest对象，代表一个HTTP请求。
     * @return String 返回客户端的ID。如果无法获取到，则返回null。
     */
    public static String getClientIdByOauthRequest(HttpServletRequest request) {
        // 将HTTP请求转换为UsernamePasswordAuthenticationToken对象
        UsernamePasswordAuthenticationToken authenticationToken = basicConvert.convert(request);
        // 如果转换成功，返回认证token的名称作为客户端ID；否则返回null
        return authenticationToken != null ? authenticationToken.getName() : null;
    }
}
